package com.example.multinetty.netty.secondprotocal;

import com.alibaba.fastjson.JSONObject;
import com.example.multinetty.netty.firstprotocal.SelfResponse;
import com.example.multinetty.netty.config.DispatchServletFactory;
import com.example.multinetty.netty.session.LocalSession;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriUtils;

import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;

@ChannelHandler.Sharable
@Component
public class LLFServletNettyHandler extends SimpleChannelInboundHandler<CompositeFullHttp> implements ApplicationContextAware {
/*
	@Autowired
	private NettyUserController nettyUserController;*/

	private ApplicationContext applicationContext;

	@Autowired
	private DispatchServletFactory dispatchServletFactory;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext){
        this.applicationContext = applicationContext;
    }

	public LLFServletNettyHandler(/*Servlet servlet*/) {
		/*this.servlet = servlet;
		this.servletContext = servlet.getServletConfig().getServletContext();*/
	}

	private MockHttpServletRequest createServletRequest(CompositeFullHttp compositeFullHttp ) {
		FullHttpRequest fullHttpRequest=compositeFullHttp.getFullHttpRequest();
		UriComponents uriComponents = UriComponentsBuilder.fromUriString(fullHttpRequest.getUri()).build();

		//MockHttpServletRequest servletRequest = new MockHttpServletRequest(this.servletContext);
		MockHttpServletRequest servletRequest = new MockHttpServletRequest();
		servletRequest.setRequestURI(uriComponents.getPath());
		servletRequest.setPathInfo(uriComponents.getPath());
		servletRequest.setMethod(fullHttpRequest.getMethod().name());

		/*HttpSession httpSession=new MockHttpSession();
		servletRequest.setSession(httpSession);*/

		if (uriComponents.getScheme() != null) {
			servletRequest.setScheme(uriComponents.getScheme());
		}
		if (uriComponents.getHost() != null) {
			servletRequest.setServerName(uriComponents.getHost());
		}
		if (uriComponents.getPort() != -1) {
			servletRequest.setServerPort(uriComponents.getPort());
		}
		fullHttpRequest.headers().set("Content-Type","application/json;charset=UTF-8");

		for (String name : fullHttpRequest.headers().names()) {
			servletRequest.addHeader(name, fullHttpRequest.headers().get(name));
		}
		servletRequest.setContent(compositeFullHttp.getContents());
		//servletRequest.addHeader("Content-Type","application/json;charset=UTF-8");
		/*try {
			ByteBuf buf=fullHttpRequest.content();
			int readable=buf.readableBytes();
			byte[] bytes=new byte[readable];
			buf.readBytes(bytes);
			bytes=compositeFullHttp.getContents();
			String contentStr=UriUtils.decode(new String(bytes,"UTF-8"),"UTF-8");
			System.out.println("http post请求写入数据:"+contentStr);
			fullHttpRequest.content().release();
		}catch (Exception ex){

		}*/

		//		ByteBuf bbContent = fullHttpRequest.content();
//		if(bbContent.hasArray()) {
//			byte[] baContent = bbContent.array();
//			servletRequest.setContent(baContent);
//		}

        // 将post请求的参数，添加到HttpServletRrequest的parameter
       /* try {
            ByteBuf buf=fullHttpRequest.content();
            int readable=buf.readableBytes();
            byte[] bytes=new byte[readable];
            buf.readBytes(bytes);
            String contentStr = UriUtils.decode(new String(bytes,"UTF-8"), "UTF-8");
            for(String params : contentStr.split("&")){
                String[] para = params.split("=");
                if(para.length > 1){
                    servletRequest.addParameter(para[0],para[1]);
                } else {
                    servletRequest.addParameter(para[0],"");
                }
            }
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
*/
		try {
			if (uriComponents.getQuery() != null) {
				String query = UriUtils.decode(uriComponents.getQuery(), "UTF-8");
				servletRequest.setQueryString(query);
			}

			for (Entry<String, List<String>> entry : uriComponents.getQueryParams().entrySet()) {
				for (String value : entry.getValue()) {
					servletRequest.addParameter(
							UriUtils.decode(entry.getKey(), "UTF-8"),
							UriUtils.decode(value, "UTF-8"));
				}
			}
		}
	/*	catch (UnsupportedEncodingException ex) {
			// shouldn't happen
		}*/
		catch (Exception ex) {
			// shouldn't happen
		}

		return servletRequest;
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		cause.printStackTrace();
		if (ctx.channel().isActive()) {
			sendError(ctx, INTERNAL_SERVER_ERROR);
		}
	}

	private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
		ByteBuf content = Unpooled.copiedBuffer(
				"Failure: " + status.toString() + "\r\n",
				CharsetUtil.UTF_8);

		FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(
				HTTP_1_1,
				status,
				content
		);
		fullHttpResponse.headers().add(CONTENT_TYPE, "text/plain; charset=UTF-8");

		// Close the connection as soon as the error message is sent.
		ctx.write(fullHttpResponse).addListener(ChannelFutureListener.CLOSE);
	}
	private void handleSession(ChannelHandlerContext context,MockHttpServletRequest servletRequest) {
		LocalSession localSession=new LocalSession(context.channel());
		servletRequest.setAttribute("channel",localSession);
	}
	@Override
	protected void channelRead0(ChannelHandlerContext channelHandlerContext, CompositeFullHttp compositeFullHttp) throws Exception {
		FullHttpRequest fullHttpRequest=compositeFullHttp.getFullHttpRequest();
		if (!fullHttpRequest.getDecoderResult().isSuccess()) {
			sendError(channelHandlerContext, BAD_REQUEST);
			return;
		}
		System.out.println("---------------------");
		//nettyUserController.getClass();

		MockHttpServletRequest servletRequest = createServletRequest(compositeFullHttp);
		MockHttpServletResponse servletResponse = new MockHttpServletResponse();
		handleSession(channelHandlerContext,servletRequest);
		
		DispatcherServlet servlet = dispatchServletFactory.getByProxy("LLFProtocal");
		//spring容器已经启动过，这个时候DispatcherServlet要进行初始化new，并进行配置。因为DispatcherServlet，无法获得实例，所以采用继承的方式新建一个。MyServlet
		servlet.service(servletRequest, servletResponse);

		HttpResponseStatus status = HttpResponseStatus.valueOf(servletResponse.getStatus());
/*
		HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status);
		for (String name : servletResponse.getHeaderNames()) {
			for (Object value : servletResponse.getHeaderValues(name)) {
				response.headers().add(name, value);
			}
		}
		// Write the initial line and the header.
		channelHandlerContext.write(response);
		InputStream contentStream = new ByteArrayInputStream(servletResponse.getContentAsByteArray());
		// Write the content and flush it.
		ChannelFuture writeFuture = channelHandlerContext.writeAndFlush(new ChunkedStream(contentStream));
		writeFuture.addListener(ChannelFutureListener.CLOSE);
*/
		String result = servletResponse.getContentAsString();
		//String result = servletResponse.getForwardedUrl();
		NettyMessage nettyMessage=(NettyMessage) JSONObject.parseObject(result,NettyMessage.class);
		/*result = StringUtils.isEmpty(result)?"":result;*/


		//list= gson.fromJson(s, new TypeToken<List<FamilyInstance>>() {}.getType());

/*
		NettyMessage nettyMessage = new NettyMessage();

		Header header = new Header();
		header.setType(MessageType.LOGIN_RESP.value());
		nettyMessage.setHeader(header);
		nettyMessage.setBody((byte)0);*/
		Header header = new Header();
		header.setType(MessageType.LOGIN_RESP.value());
		nettyMessage.setHeader(header);

		//nettyMessage.setBody((byte)0);

		nettyMessage.setBody(new Byte((byte)0));//如果从Controller层转过来的，byte会翻译为Integer

		/*FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status,Unpooled.copiedBuffer(result,CharsetUtil.UTF_8));
		SelfResponse selfResponse=new SelfResponse(response);
		response.headers().set("Content-Type", "text/json;charset=UTF-8");
		response.headers().set("Access-Control-Allow-Origin", "*");
		response.headers().set("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With,X-File-Name");
		response.headers().set("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
		response.headers().set("Content-Length", Integer.valueOf(response.content().readableBytes()));
		response.headers().set("Connection", "keep-alive");
		//ChannelFuture writeFuture = channelHandlerContext.writeAndFlush(response);
		int readable=response.content().readableBytes();
		byte[] bytes=new byte[readable];
		servletResponse.getOutputStream().write(bytes);*/
		//NettyMessage nettyMessage= (NettyMessage)JSONObject.parse(bytes);

		//ChannelFuture writeFuture = channelHandlerContext.writeAndFlush(nettyMessage);
		//writeFuture.addListener(ChannelFutureListener.CLOSE);
		channelHandlerContext.executor().scheduleAtFixedRate(new LLFServletNettyHandler.HeartBeatTask(channelHandlerContext), 0, 50000,
				TimeUnit.MILLISECONDS);

	}
	private class HeartBeatTask implements Runnable{
		private final ChannelHandlerContext ctx;
		public HeartBeatTask(final ChannelHandlerContext ctx) {
			this.ctx = ctx;
		}
		@Override
		public void run() {
			/*NettyMessage heatBeat = buildHeatBeat();
			LOG.info("Client send heart beat messsage to server : ---> "
					+ heatBeat);*/
			NettyMessage nettyMessage=new NettyMessage();
			Header header = new Header();
			header.setType(MessageType.LOGIN_RESP.value());
			nettyMessage.setHeader(header);
			nettyMessage.setBody(new Byte((byte)0));

			ctx.writeAndFlush(nettyMessage);
		}
	}

}
